package com.pmpd.activity.service.api.impl;

import com.dmap.base.cache.impl.BaseCacheDaoStringImpl;
import com.dmap.base.units.DateUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pmpd.activity.bo.cache.TaskAlarmCache;
import com.pmpd.activity.constants.ActivityConstant;
import com.pmpd.activity.bo.api.RunDistanceBo;
import com.pmpd.activity.bo.api.StepAndSleepInfoBo;
import com.pmpd.activity.constants.ActivityRedisConstant;
import com.pmpd.activity.controller.api.param.ActivityProgressParam;
import com.pmpd.activity.dao.ActivityProgressMapper;
import com.pmpd.activity.dao.ActivityTaskMapper;
import com.pmpd.activity.dao.ActivityUserMapper;
import com.pmpd.activity.po.*;
import com.pmpd.activity.rpc.ActivityRunRpc;
import com.pmpd.activity.rpc.ActivitySenorRpc;
import com.pmpd.activity.service.api.ApiActivityProgressService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author liuying
 * @Description 活动每日进程服务层实现
 * @Date 15:08 2018/6/7
 */
@Service
public class ApiActivityProgressServiceImpl extends BaseCacheDaoStringImpl implements ApiActivityProgressService {

    private static final Logger logger = LoggerFactory.getLogger(ApiActivityProgressServiceImpl.class);

    @Resource
    private ActivityProgressMapper activityProgressMapper;

    @Resource
    private ActivitySenorRpc activitySenorRpc;

    @Resource
    private ActivityRunRpc activityRunRpc;

    @Resource
    private ActivityTaskMapper activityTaskMapper;

    @Resource
    private ActivityUserMapper activityUserMapper;

    @Override
    public ActivityProgress synchrodata(ActivityProgress progressParam) {
        long seconds = System.currentTimeMillis() / 1000;

        //创建需要更新的数据对象
        ActivityProgress updateData = new ActivityProgress();

        //查询该活动该用户当天任务
        ActivityTask task = getProgress(progressParam.getActivityId(), progressParam.getUserId(), DateUtil.getDay0ByTime(seconds));
        if (task == null){
            return null;
        }

        //判断处于哪种状态（1 未完成，2 未达标，3 达成）
        int sleepState = isInTheRange(progressParam.getSleepNumber(), 0, task.getSleepGoal());
        int stepState = isInTheRange(progressParam.getStepNumber(), 0, task.getStepGoal());
        int runState = isInTheRange(progressParam.getRunNumber(), 0, task.getRunGoal());
        updateData.setStatus(getState(sleepState, stepState, runState));

        //组装查询条件
        ActivityProgressExample example = new ActivityProgressExample();
        example.createCriteria().andActivityIdEqualTo(progressParam.getActivityId())
                .andUserIdEqualTo(progressParam.getUserId())
                .andTaskTimeEqualTo(progressParam.getTaskTime());

        //组装需要更新的数据
        updateData.setRunNumber(progressParam.getRunNumber());
        updateData.setStepNumber(progressParam.getStepNumber());
        updateData.setSleepNumber(progressParam.getSleepNumber());
        updateData.setUpdateTime(seconds);

        int success = activityProgressMapper.updateByExampleSelective(updateData, example);
        return (success == 1) ? updateData : null;
    }

    private int getState(int stateA, int stateB, int stateC) {
        if (stateA == ActivityConstant.STATE_PROGRESS_NOT_COMPLETE || stateB == ActivityConstant.STATE_PROGRESS_NOT_COMPLETE
                || stateC == ActivityConstant.STATE_PROGRESS_NOT_COMPLETE) {
            //有一项未完成则为未完成
            return ActivityConstant.STATE_PROGRESS_NOT_COMPLETE;
        } else if (stateA == ActivityConstant.STATE_PROGRESS_NOT_QUALIFIED || stateB == ActivityConstant.STATE_PROGRESS_NOT_QUALIFIED
                || stateC == ActivityConstant.STATE_PROGRESS_NOT_QUALIFIED) {
            //没有未完成任务的情况下，有一项未达标则为未达标
            return ActivityConstant.STATE_PROGRESS_NOT_QUALIFIED;
        } else {
            //没有未完成也没有未达标的任务即为完成
            return ActivityConstant.STATE_PROGRESS_COMPLETE;
        }

    }

    /**
     * @param value      需判断的数据
     * @param rangeBegin 范围开始值
     * @param rangeEnd   范围结束值
     * @Author liuying
     * @Description 判断数据处于哪个状态
     * @Date 19:50 2018/6/11
     */
    private int isInTheRange(int value, int rangeBegin, int rangeEnd) {
        int state = ActivityConstant.STATE_PROGRESS_NOT_COMPLETE;
        if (value < rangeBegin) {
            logger.error("Sleep or step or run data error， value is {}， range is {} to {}.", value, rangeBegin, rangeEnd);
        } else {
            if (value >= rangeEnd) {
                state = ActivityConstant.STATE_PROGRESS_COMPLETE;
            } else if (value >= (rangeEnd * ActivityConstant.QUALIFIED_PROPORTION)) {
                state = ActivityConstant.STATE_PROGRESS_NOT_QUALIFIED;
            } else {
                state = ActivityConstant.STATE_PROGRESS_NOT_COMPLETE;
            }
        }
        return state;
    }

    @Override
    public int getFinishDays(long userId, long activityId) {
        ActivityProgressExample example = new ActivityProgressExample();
        example.createCriteria().andUserIdEqualTo(userId).andActivityIdEqualTo(activityId)
                .andStatusEqualTo(ActivityConstant.STATE_PROGRESS_COMPLETE);
        return activityProgressMapper.countByExample(example);
    }

    @Override
    public ActivityProgress addProgress(long activityId, long userId, int type, long seconds) {
        ActivityProgress activityProgress = new ActivityProgress();
        activityProgress.setActivityId(activityId);
        activityProgress.setUserId(userId);
        activityProgress.setTaskDay(1);
        activityProgress.setTaskTime(DateUtil.getDay0ByTime(seconds));

        //获取当天的运动睡眠数据
        List<Long> userIds = new ArrayList<>();
        userIds.add(userId);
        int runData = 0, sleepData = 0, stepData = 0;
        List<StepAndSleepInfoBo> sleepDatas = activitySenorRpc.selectSleepAndStep(userIds, DateUtil.getDay0ByTime(seconds), ActivityConstant.STATE_SLEEP);
        List<StepAndSleepInfoBo> stepDatas = activitySenorRpc.selectSleepAndStep(userIds, DateUtil.getDay0ByTime(seconds), ActivityConstant.STATE_STEP);
        List<RunDistanceBo> runDatas = activityRunRpc.selectRunData(userIds, DateUtil.getDay0ByTime(seconds));
        if (CollectionUtils.isNotEmpty(sleepDatas) && CollectionUtils.isNotEmpty(stepDatas) && CollectionUtils.isNotEmpty(runDatas)) {
            sleepData = sleepDatas.get(0).getSleepTime();
            stepData = stepDatas.get(0).getStepNumber();
            runData = runDatas.get(0).getDistance();
        }

        activityProgress.setRunNumber(runData);
        activityProgress.setSleepNumber(sleepData);
        activityProgress.setStepNumber(stepData);

        //查询该活动该用户进程
        ActivityTaskExample taskExample = new ActivityTaskExample();
        taskExample.createCriteria().andActivityIdEqualTo(activityId).andTypeEqualTo(type).andTaskDayEqualTo(1);
        ActivityTask task = activityTaskMapper.selectByExample(taskExample).get(0);
        if (task == null){
            return null;
        }

        //判断处于哪种状态（1 未完成，2 未达标，3 达成）
        int sleepState = isInTheRange(sleepData, 0, task.getSleepGoal());
        int stepState = isInTheRange(stepData, 0, task.getStepGoal());
        int runState = isInTheRange(runData, 0, task.getRunGoal());
        activityProgress.setStatus(getState(sleepState, stepState, runState));

        activityProgress.setCreateTime(seconds);
        activityProgress.setUpdateTime(activityProgress.getCreateTime());

        int success = activityProgressMapper.insert(activityProgress);

        return success == 1 ? activityProgress : null;
    }

    @Override
    public int bulkInsert(List<ActivityUser> ActivityUsers) {
        long seconds = System.currentTimeMillis() / 1000;

        //提前组装每个活动进程数据
        List<ActivityProgress> activityProgresses = new ArrayList<>();
        for (ActivityUser user : ActivityUsers) {
            //判断是否在用户参加的活动时间范围内
            if ((DateUtil.getDay24ByTime(seconds) + 1) < user.getEndTime()) {

                ActivityProgress activityProgress = new ActivityProgress();
                activityProgress.setActivityId(ActivityConstant.SEVEN_DAYS_TRAINING_ID);
                activityProgress.setTaskTime(DateUtil.getDay24ByTime(seconds) + 1);
                activityProgress.setRunNumber(0);
                activityProgress.setSleepNumber(0);
                activityProgress.setStepNumber(0);
                activityProgress.setStatus(1);
                activityProgress.setCreateTime(seconds);
                activityProgress.setUpdateTime(activityProgress.getCreateTime());

                activityProgress.setUserId(user.getUserId());

                //计算当前为第几天
                long joinZero = DateUtil.getDay0ByTime(user.getJoinTime());
                int intervalDays = new Long((DateUtil.getDay0ByTime(seconds) - joinZero) / (3600 * 24)).intValue();
                activityProgress.setTaskDay(2 + intervalDays);
                activityProgresses.add(activityProgress);
            }
        }

        return activityProgressMapper.bulkInsert(activityProgresses);

    }

    @Override
    public boolean bulkUpdate() {
        long seconds = System.currentTimeMillis() / 1000;
        long yesterdayZero = DateUtil.getDay0ByTime(seconds) - 3600 * 24;

        //查询该活动前一天的所有用户进程
        List<ActivityProgressTask> progressTasks = activityProgressMapper.getProgresses(ActivityConstant.SEVEN_DAYS_TRAINING_ID, yesterdayZero);

        if (CollectionUtils.isNotEmpty(progressTasks)){
            List<Long> userIds = new ArrayList<>();
            progressTasks.forEach(progress ->
                    userIds.add(progress.getUserId())
            );

            //得到所有用户运动睡眠数据
            logger.info("---------------批量获取计步数据开始------------");
            List<StepAndSleepInfoBo> stepInfos = activitySenorRpc.selectSleepAndStep(userIds, yesterdayZero, ActivityConstant.STATE_STEP);
            logger.info("---------------批量获取计步数据结束------------");
            logger.info("---------------批量获取睡眠数据开始------------");
            List<StepAndSleepInfoBo> sleepInfos = activitySenorRpc.selectSleepAndStep(userIds, yesterdayZero, ActivityConstant.STATE_SLEEP);
            logger.info("---------------批量获取睡眠数据结束------------");
            logger.info("---------------批量获取跑步数据开始------------");
            List<RunDistanceBo> runInfos = activityRunRpc.selectRunData(userIds, yesterdayZero);
            logger.info("---------------批量获取跑步数据结束------------");

            //循环将所有数据放进去
            List<ActivityProgress> progresses = new ArrayList<>();
            ActivityProgress activityProgress;
            for (ActivityProgressTask progressTask : progressTasks) {
                //加入本来有的数据
                activityProgress = new ActivityProgress(progressTask);

                //更新计步数据
                for (StepAndSleepInfoBo item : stepInfos) {
                    if (item.getUserId() == activityProgress.getUserId()) {
                        activityProgress.setStepNumber(item.getStepNumber());
                        break;
                    }
                }

                //更新睡眠数据
                for (StepAndSleepInfoBo item : sleepInfos) {
                    if (item.getUserId() == activityProgress.getUserId()) {
                        activityProgress.setSleepNumber(item.getSleepTime());
                        break;
                    }
                }

                //更新跑步数据
                for (RunDistanceBo item : runInfos) {
                    if (item.getUserId() == activityProgress.getUserId()) {
                        activityProgress.setRunNumber(item.getDistance());
                        break;
                    }
                }

                //更新用户当日任务进行状态（1 未完成，2 未达标，3 达成）
                int sleepState = isInTheRange(activityProgress.getSleepNumber(), 0, progressTask.getSleepGoal());
                int stepState = isInTheRange(activityProgress.getStepNumber(), 0, progressTask.getStepGoal());
                int runState = isInTheRange(activityProgress.getRunNumber(), 0, progressTask.getRunGoal());
                activityProgress.setStatus(getState(sleepState, stepState, runState));

                activityProgress.setUpdateTime(seconds);
                progresses.add(activityProgress);
            }

            logger.info("---------------用户昨日进程数据更新开始------------");
            int success = activityProgressMapper.bulkUpdate(progresses);
            if (success == progresses.size()) {
                logger.info("---------------用户昨日进程数据更新成功------------");
                return true;
            } else {
                logger.error("---------------用户昨日进程数据更新失败------------");
                return false;
            }
        } else {
            return true;
        }
    }

    @Override
    public List<ActivityUser> getBulkProgress(long sevenDaysTrainingId, int status) {
        return activityProgressMapper.getBulkProgress(sevenDaysTrainingId, status);
    }

    @Override
    public ActivityProgress addNextDayProgress(long activityId, long userId, long seconds) {
        ActivityProgress activityProgress = new ActivityProgress();
        activityProgress.setActivityId(activityId);
        activityProgress.setTaskTime(DateUtil.getDay24ByTime(seconds) + 1);
        activityProgress.setRunNumber(0);
        activityProgress.setSleepNumber(0);
        activityProgress.setStepNumber(0);
        activityProgress.setStatus(1);
        activityProgress.setCreateTime(seconds);
        activityProgress.setUpdateTime(activityProgress.getCreateTime());
        activityProgress.setUserId(userId);
        activityProgress.setTaskDay(1);

        int success = activityProgressMapper.insert(activityProgress);
        return (success == 1) ? activityProgress : null;
    }

    @Override
    public ActivityTask getProgress(long activityId, long userId, long timestamp) {
        //查询该用户信息
        ActivityUserExample userExample = new ActivityUserExample();
        userExample.createCriteria().andActivityIdEqualTo(activityId).andUserIdEqualTo(userId);
        List<ActivityUser> users = activityUserMapper.selectByExample(userExample);
        if (CollectionUtils.isEmpty(users)){
            logger.error("-------------该用户未参加该活动---------------");
            return null;
        }

        //得到该用户明日taskDay
        ActivityUser user = users.get(0);
        long joinZero = DateUtil.getDay0ByTime(user.getJoinTime());
        int taskDay = new Long((DateUtil.getDay0ByTime(timestamp) - joinZero) / (3600 * 24)).intValue() + 1;

        ActivityTaskExample taskExample = new ActivityTaskExample();
        taskExample.createCriteria().andActivityIdEqualTo(activityId).andTypeEqualTo(user.getType()).andTaskDayEqualTo(taskDay);
        List<ActivityTask> tasks = activityTaskMapper.selectByExample(taskExample);
        if (CollectionUtils.isEmpty(tasks)){
            return null;
        }
        return tasks.get(0);
    }

    @Override
    public String isSetTaskAlarm(ActivityProgressParam param) {
        long seconds = System.currentTimeMillis() / 1000;

        //从缓存中得到设置计划的value
        String valueString = getKV(ActivityRedisConstant.CACHE_SENOR_TIME_STAMP_CODE + param.getUserId());

        if (StringUtils.isNotEmpty(valueString)) {
            //解析
            TaskAlarmCache cache;
            ObjectMapper mapper = new ObjectMapper();
            try {
                cache = mapper.readValue(valueString, TaskAlarmCache.class);
            } catch (IOException ie) {
                logger.error("------------设置任务缓存信息解析失败！---------------------");
                return null;
            }

            //校验是否为所需缓存
            if ((cache.getActivityId() == Long.parseLong(param.getActivityId())) && (cache.getTimestamp() == DateUtil.getDay0ByTime(seconds))){
                return valueString;
            }
        }

        return null;
    }

    @Override
    public boolean addTaskAlarm(ActivityProgressParam param) {
        long seconds = System.currentTimeMillis() / 1000;

        TaskAlarmCache cache = new TaskAlarmCache();
        cache.setActivityId(Long.parseLong(param.getActivityId()));
        cache.setTimestamp(DateUtil.getDay0ByTime(seconds));

        return addKV(ActivityRedisConstant.CACHE_SENOR_TIME_STAMP_CODE + param.getUserId(), cache.toString()
                , new Long((DateUtil.getDay24ByTime(seconds) + 1) - seconds).intValue());
    }

}
